package sysu.el.graph.undi;

import sysu.el.array.algors.Sig;
import sysu.el.graph.GTMatrix;
import sysu.el.graph.GraphConstants;
import sysu.el.matrix.ints.MatInt;
import sysu.el.matrix.ints.MatIntLib;

public class UndiGTMatrix extends GTMatrix implements UndiGTInterface{
	// Basic Graph Layout Information

	/* ******************************************************************** */
	/* ************************* Constructors ***************************** */
	/* ******************************************************************** */

	public UndiGTMatrix(){
		super();
	}

	public UndiGTMatrix(int nodeNum){
		super(nodeNum);
	}

	public UndiGTMatrix(int node_num, int wei[][]){
		super(node_num);
		for (int i=0; i<node_num; i++){
			for (int j=0; j<node_num; j++){
				w[i][j] = wei[i][j];
			}
		}
	}

	public UndiGTMatrix(UndiGTAdjList m){
		super(m.getNodeNum());
		for (int i=0; i<this.getNodeNum(); ++i){
			int[] list = m.getList(i);
			for (int j=0; j<m.getDegree(i); ++j)
				this.addEdge(i, list[j], 1);
		}
	}
	
	public UndiGTMatrix(UndiGTAdjListVal m){
		super(m.getNodeNum());
		for (int i=0; i<this.getNodeNum(); ++i){
			int[] list = m.getList(i);
			for (int j=0; j<m.getDegree(i); ++j)
				this.addEdge(i, list[j], m.getVal(i, j));
		}
	}

	/* ******************************************************************** */
	/* *************************** Wrappers ******************************* */
	/* ******************************************************************** */
	public static UndiGTMatrix wrap(int wei[][]){
		UndiGTMatrix m = new UndiGTMatrix();
		m.w = wei;
		return m;
	}

	/* ******************************************************************** */
	/* ************************* Essential OP ***************************** */
	/* ******************************************************************** */
	public String wToString(){
		//    	StringBuffer sb = new StringBuffer();
		//    	for (int i=0; i<this.nodeNum; i++)
		//    		sb.append(Sig.mkStrBuf(this.nodeNum, this.w[i], "\t").append("\n"));
		//    	return new String(sb);
		return Sig.mkString(this.getNodeNum(), this.getNodeNum(), this.w, "\n", "\t");
	}

	@Override
	public void setChain(int num, int chain[], int val){
		for (int i=0; i<num-1; i++){
			this.w[chain[i]][chain[i+1]] = val;
			this.w[chain[i+1]][chain[i]] = val;
		}
	}

	/* ******************************************************************** */
	/* ************************* Interface OP ***************************** */
	/* ******************************************************************** */

	@Override
	public void addEdge(int i, int j, int val){
		//    	this.edgeNum ++;
		this.w[i][j] = val;
		this.w[j][i] = val;
	}

	@Override
	public int getDegree(int node) {
		int sum = 0 ;
		for (int i=0; i<this.getNodeNum(); i++)
			if (this.w[node][i] != GraphConstants.NULL_EDGE)
				sum ++;
		return sum;
	}

	/**
	 * Provide an immediate getter for the degree which is dependent on the getList()
	 * for that is the side effect on the getList();
	 * @return
	 */
	public int getDegreeWithGetList(){
		return counter;
	}
	
	private int counter;
	@Override
	public int[] getList(int node) {
		int[] list = new int[this.getNodeNum()];
		counter = 0;
		for (int i=0; i<this.getNodeNum(); i++)
			if (this.w[node][i] != GraphConstants.NULL_EDGE)
				list[counter++] = i;
		return list;
	}

	@Override
	public int getEdgeNum() {
		// TODO Auto-generated method stub
		return 0;
	}

}
